對於 PHP Stream 的概念網路上的資源甚少,儘管這是從 PHP 4.3 開始就存在的功能,卻極少見到有開發者會去使用這樣的 Feature(或是使用這樣的 Feature 但不自知)。
先定義「Stream」是怎麼樣的存在,有助於理解它的意義:
起點與終點可以允許為
詳細的列表可以參閱官方文件
事實上,我們時常會時用到 Stream,只是通常不自知。
舉例而言,file_get_content() 函式中所要求的參數就是 Stream,我們可以在裡面自由填入 http:// 或 file://(如果沒有填的話預設是 file://)以取得資源。
許多與「檔案操作」類似的函式也都是以流為基本型式:fopen(), fclose(), fgets(), fwrite(), fseek()。
值得一提的是,include 及 require 也會受到 stream 的影響,所以如果系統存在 LFI 的話是相當危險的(關於 LFI 與 Stream 我會再開一篇文章討論)
註:PHP 預設會將
allow_url_include關閉,所以通常無法直接 include 一個遠端的 PHP 檔案造成 RCE。
php://在 PHP 中內建了一系列的 php:// 的 Stream Protocal,可以利用這些 protocol 強化 PHP 的某些功能。
取得所有的 input 通常來源於 HTTP body,值得注意的是,由這個 Stream 取得的內容是 Raw Body,所以需要自行解析。
取得由標準輸入所進入的內容,類似於 C++ 中的 cin,通常用於取得 Command Line 時的輸入。
將內容輸出至標準輸出中,類似於 C++ 的 cout。值得注意的是它只能寫不能讀(也無法用 fseek() 尋址)
將內容輸出至記憶體中,可用於測試時期或一些快取資料。值得注意的是記憶體是有限的,所以如果記憶體耗盡可能會產生無法開啟的錯誤。
與 php://memory 相似,優先會將資料存入記憶體,但若記憶體空間不足會把資料寫進臨時檔案。
PHP 存在一些超全域變數,然而隨著 HTTP 的演進,卻遲遲沒有增加 $_PUT 或 $_PATCH 等變數。
即便到了 2019 的今天,如果要取得 PUT 或 PATCH method 的 request body,仍然要透過 Stream。
<?php
$body = file_get_contents('php://input');
// 在這邊拿到的 $body 會是 raw http body(如下所示),需要自行解析它
// $body = 'name=Vincent&age=25';
甚至如果要做到「用 PUT Method 上傳檔案」,也是用類似的做法(但是要注意的是 enctype=multipart/form-data 的解析問題)
PHP 官方文件中有對此進行解釋,但事實上它會無法使用如 $_FILES 等常用的上傳檔案處理方式。
之後 Stream 應該會再開兩篇文章,說明如何建立自定義的 Stream 及如何使用 Filter。